package com.example.voucher.enums;

import java.math.BigDecimal;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.example.voucher.common.VoucherConstant;
import com.google.common.collect.Maps;

public enum ReducingRuleEnum {

    FIND_FIRST(VoucherConstant.REDUCING_RULE_FIRST, "取第一个"),   // WARNING:code不要变更：配置文件有用到
    SUMMARIZING(VoucherConstant.REDUCING_RULE_SUM_NUMER, "Number汇总"), // WARNING:code不要变更：配置文件有用到
    JOINING(VoucherConstant.REDUCING_RULE_JOIN_STRING, "字符串拼接"), // WARNING:code不要变更：配置文件有用到
    JOINING_DISTINCT(VoucherConstant.REDUCING_RULE_DISTINCT_JOIN_STRING, "字符串消重拼接"), // WARNING:code不要变更：配置文件有用到
    SUMMARIZING_QTY_UNIT(VoucherConstant.REDUCING_RULE_QTY_UNIT_SUM, "特殊的数量单位求和拼接");// WARNING:code不要变更：配置文件有用到

    public static final Pattern QTY_UNIT_PATTERN = Pattern.compile("^((-?\\d+)(\\.\\d+)?)(.*)$");

    private String code;
    private String desc;

    private ReducingRuleEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public static ReducingRuleEnum getByCode(String code) {
        for (ReducingRuleEnum e : ReducingRuleEnum.values()) {
            if (e.code.equals(code)) {
                return e;
            }
        }
        return null;
    }

    public static String getDescByCode(String code) {
        for (ReducingRuleEnum e : ReducingRuleEnum.values()) {
            if (e.code.equals(code)) {
                return e.getDesc();
            }
        }
        return null;
    }
    
    public static <T> BinaryOperator<?> combinerBinaryOperator(String ruleCode, Class<T> cls, Object param) {
        ReducingRuleEnum rule = getByCode(ruleCode);
        if (null == rule) {
            throw new RuntimeException(String.format("入参有误：", ruleCode));
        }
        switch (rule) {
            case FIND_FIRST:
                return (t1, t2) -> t1;
            case SUMMARIZING:
                if (BigDecimal.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> ((BigDecimal)t1).add((BigDecimal)t2);
                } else if (Long.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> Long.sum((Long)t1, (Long)t2);
                } else if (Integer.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> Integer.sum((Integer)t1, (Integer)t2);
                } else {
                    throw new RuntimeException("暂不支持的操作");
                }
            case JOINING:
                if (CharSequence.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> {
                        CharSequence l = t1 == null ? "" : (CharSequence)t1;
                        CharSequence r = t2 == null ? "" : (CharSequence)t2;
                        CharSequence delimiter =
                            (param == null || !CharSequence.class.isAssignableFrom(param.getClass())) ? ""
                                : (CharSequence)param;
                        return new StringBuilder(l).append(delimiter).append(r).toString();
                    };
                } else {
                    throw new RuntimeException("暂不支持的操作");
                }
            case JOINING_DISTINCT:
                if (String.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> {
                        String l = t1 == null ? "" : (String)t1;
                        String r = t2 == null ? "" : (String)t2;
                        String delimiter =
                            (param == null || !String.class.isAssignableFrom(param.getClass())) ? " "
                                : (String)param;
                        Set<String> strSet = Stream.of(l.split(delimiter)).collect(Collectors.toSet());
                        if (strSet.contains(r)) {
                            // 消重
                            return l;
                        }
                        return new StringBuilder(l).append(delimiter).append(r).toString();
                    };
                } else {
                    throw new RuntimeException("暂不支持的操作");
                }
            case SUMMARIZING_QTY_UNIT:
                if (String.class.isAssignableFrom(cls)) {
                    return (t1, t2) -> {
                        String l = t1 == null ? "" : (String)t1;
                        String r = t2 == null ? "" : (String)t2;
                        String delimiter =
                            (param == null || !String.class.isAssignableFrom(param.getClass())) ? " "
                                : (String)param;
                        // 解析l
                        Map<String, BigDecimal> unitMap = Maps.newHashMap();
                        Set<String> strSet = Stream.of(l.split(delimiter)).collect(Collectors.toSet());
                        for (String qtyUnit : strSet) {
                            Matcher matcher = QTY_UNIT_PATTERN.matcher(qtyUnit);
                            if (matcher.matches()) {
                                BigDecimal qty = new BigDecimal(matcher.group(1));
                                String unit = matcher.group(4);
                                unitMap.put(unit, qty);
                            }
                        }
                        // 解析r, l+r
                        Matcher matcher = QTY_UNIT_PATTERN.matcher(r);
                        if (matcher.matches()) {
                            BigDecimal qty = new BigDecimal(matcher.group(1));
                            String unit = matcher.group(4);
                            if (unitMap.containsKey(unit)) {
                                BigDecimal qtySum = unitMap.get(unit);
                                qty = qtySum.add(qty);
                            }
                            unitMap.put(unit, qty);
                        }
                        // unitMap ---> String
                        StringBuilder str = new StringBuilder();
                        for (Entry<String, BigDecimal> entry : unitMap.entrySet()) {
                            if (str.length() > 0) {
                                str.append(delimiter);
                            }
                            str.append(entry.getValue().stripTrailingZeros().toPlainString()).append(entry.getKey());
                        }
                        return str.toString();
                    };
                } else {
                    throw new RuntimeException("暂不支持的操作");
                }                
            default:
                break;
        }
        return (t1, t2) -> t1;
    }

    public String getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

}
